using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Mvc;
using RMH.DataAccess;
using RMH.Entities;
using RMH.Services;
using System.Linq;

namespace RMH.Web.Models.Binders
{
    public class PatientBinder : IModelBinder
    {
        private IPatientService patientService;
        private ICountyService countyService;
        private IDiagnosisService diagnosisService;
        private ISupportPersonService supportPersonService;

        public PatientBinder(IPatientService patientRepository, ICountyService countyRepository, IDiagnosisService diagnosisService, ISupportPersonService supportPersonService)
        {
            this.patientService = patientRepository;
            this.supportPersonService = supportPersonService;
            this.diagnosisService = diagnosisService;
            this.countyService = countyRepository;
        }

        public PatientBinder()
        {
            patientService = Container.Resolve<IPatientService>();
            countyService = Container.Resolve<ICountyService>();
            diagnosisService = Container.Resolve<IDiagnosisService>();
            supportPersonService = Container.Resolve<ISupportPersonService>();
        }

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var form = controllerContext.HttpContext.Request.Form;

            Patient patient = new Patient();

            if (!String.IsNullOrEmpty(form["Id"]) && form["Id"].ToInt() > 0)
                patient = patientService.Get(Int32.Parse(form["Id"]));

            PersonBinder personBinder = new PersonBinder();
            personBinder.BindModel(controllerContext, bindingContext, patient);

            DateTime dateContainer;
            if (!String.IsNullOrEmpty(form["DateOfBirth"]))
            {
                if (DateTime.TryParse(form["DateOfBirth"], out dateContainer))
                    patient.DateOfBirth = dateContainer;
            }
            else
                patient.DateOfBirth = null;
            if (!String.IsNullOrEmpty(form["DateOfDeath"]))
            {
                if (DateTime.TryParse(form["DateOfDeath"], out dateContainer))
                    patient.DateOfDeath = dateContainer;
            }
            else
                patient.DateOfDeath = null;

            if(!string.IsNullOrEmpty(form["CountyId"]))
            {
                patient.County = countyService.Get(int.Parse(form["CountyId"]));
            }

            if( !string.IsNullOrEmpty(form["SupportPerson"]) && !string.IsNullOrEmpty(form["RelationShipType"]))
            {
                string formPersonIds = form["SupportPerson"];
                string formRelationshipTypeIds = form["RelationShipType"];

                
                var sourcePersonIds = formPersonIds.Split(',');
                var sourceRelationshipTypeIds = formRelationshipTypeIds.Split(',');

                var relationshipsToDelete = new List<Relationship>();
                foreach(var relationship in patient.Relationships)
                {
                    if(!sourcePersonIds.Contains(relationship.Id.ToString()))
                    {
                        relationshipsToDelete.Add(relationship);
                    }
                }
                foreach(var relationship in relationshipsToDelete)
                {
                    patient.Relationships.Remove(relationship);
                }

                for (var relationIndex = 0; relationIndex < sourcePersonIds.Length; relationIndex++)
                {
                    int supportPersonId = Convert.ToInt32(sourcePersonIds[relationIndex]);
                    RelationshipType relationshipTypeId = (RelationshipType)Convert.ToInt32(sourceRelationshipTypeIds[relationIndex]);
                    var relationship=  new Relationship
                        {Patient = patient, SupportPerson = 
                            supportPersonService.Get(supportPersonId), 
                            Type = relationshipTypeId};


                    if( !patient.Relationships.Any( r => r.SupportPerson.Id == supportPersonId ) )
                    {
                        patient.Relationships.Add(relationship);
                    }

                }
            }


            getDiagnosis(form, patient);

            return patient;
        }


        private void setSupportPeople(NameValueCollection form, Patient patient)
        {
            if (string.IsNullOrEmpty(form["SupportPerson"])) return;

            var allPeople = new List<SupportPerson>();
            foreach (var supportPersonId in form["SupportPerson"].Split(','))
            {
                var id = Int32.Parse(supportPersonId.Trim());
                allPeople.Add(supportPersonService.Get(id));
            }
                       

        }

        // TODO: refactor this monstrosity.  there're unit tests, so refactoring is safe
        private void getDiagnosis(NameValueCollection form, Patient patient)
        {
            if (!string.IsNullOrEmpty(form["Diagnosis"]))
            {
                
                List<Diagnosis> allDiagnosis = new List<Diagnosis>();                
                foreach (var diagnosisId in form["Diagnosis"].Split(','))
                {
                    var id = Int32.Parse(diagnosisId.Trim());
                    allDiagnosis.Add(diagnosisService.Get(id));
                }

                foreach (var diagnosis in allDiagnosis)
                {
                    if (!patient.Diagnoses.Contains(diagnosis))
                    {
                        Console.WriteLine("adding " + diagnosis);
                        patient.Diagnoses.Add(diagnosis);
                    }
                }

                var diagnosisToRemove = new List<Diagnosis>();
                foreach (var diagnosis in patient.Diagnoses)
                {
                    if (!allDiagnosis.Contains(diagnosis))
                    {                        
                        diagnosisToRemove.Add(diagnosis);
                    }
                }

                foreach (var diagnosis in diagnosisToRemove)
                {
                    Console.WriteLine("removing " + diagnosis);
                    patient.Diagnoses.Remove(diagnosis);
                }
            }
        }
    }
}